from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.service import Service
import csv
import os
import time
import random
import pymysql

# 设置 ChromeDriver 路径
service = Service("D:/迅雷下载/chrome-win64/chrome-win64/chromedriver.exe")

# 创建浏览器实例
options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)

driver = webdriver.Chrome(service=service, options=options)

# CSV文件路径
csv_file = "book_info.csv"
# CSV表头
fieldnames = [
    'book_name', 'status', 'category',
    'total_clicks', 'total_recommendations',
    'weekly_recommendations', 'total_words',
    'latest_chapter'
]

# 创建CSV文件并写入表头
if not os.path.exists(csv_file):
    with open(csv_file, 'w', newline='', encoding='utf-8-sig') as f:
        writer = csv.DictWriter(f, fieldnames=fieldnames)
        writer.writeheader()

# 数据库配置
db_config = {
    'host': 'localhost',
    'port': 3306,
    'user': 'root',
    'password': '123456',
    'charset': 'utf8mb4'
}

# 数据库名和表名
DB_NAME = 'book_crawler'
TABLE_NAME = 'book_info'


def init_database():
    """初始化数据库和表"""
    # 连接MySQL服务器（不指定数据库）
    conn = pymysql.connect(
        host=db_config['host'],
        port=db_config['port'],
        user=db_config['user'],
        password=db_config['password'],
        charset=db_config['charset']
    )

    try:
        with conn.cursor() as cursor:
            # 检查数据库是否存在
            cursor.execute("SHOW DATABASES LIKE %s", (DB_NAME,))
            if cursor.fetchone() is None:
                print(f"创建数据库: {DB_NAME}")
                cursor.execute(f"CREATE DATABASE {DB_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci")
            else:
                print(f"数据库 {DB_NAME} 已存在")

            # 切换到目标数据库
            cursor.execute(f"USE {DB_NAME}")

            # 检查表是否存在
            cursor.execute("SHOW TABLES LIKE %s", (TABLE_NAME,))
            if cursor.fetchone() is None:
                print(f"创建表: {TABLE_NAME}")
                # 创建表
                create_table_sql = f"""
                CREATE TABLE {TABLE_NAME} (
                    id INT AUTO_INCREMENT PRIMARY KEY,
                    book_name VARCHAR(255) NOT NULL,
                    status VARCHAR(50),
                    category VARCHAR(100),
                    total_clicks VARCHAR(50),
                    total_recommendations VARCHAR(50),
                    weekly_recommendations VARCHAR(50),
                    total_words VARCHAR(50),
                    latest_chapter VARCHAR(255)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
                """
                cursor.execute(create_table_sql)
            else:
                print(f"表 {TABLE_NAME} 已存在")

        conn.commit()
        print("数据库初始化完成")
    except Exception as e:
        print(f"初始化数据库时出错: {e}")
    finally:
        conn.close()


def save_to_database(book_data):
    """将书籍数据保存到数据库"""
    conn = pymysql.connect(
        host=db_config['host'],
        port=db_config['port'],
        user=db_config['user'],
        password=db_config['password'],
        db=DB_NAME,
        charset=db_config['charset']
    )

    try:
        with conn.cursor() as cursor:
            # 插入数据
            sql = f"""
            INSERT INTO {TABLE_NAME} (
                book_name, status, category, 
                total_clicks, total_recommendations, 
                weekly_recommendations, total_words, 
                latest_chapter
            ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
            """
            cursor.execute(sql, (
                book_data['book_name'],
                book_data['status'],
                book_data['category'],
                book_data['total_clicks'],
                book_data['total_recommendations'],
                book_data['weekly_recommendations'],
                book_data['total_words'],
                book_data['latest_chapter']
            ))

        conn.commit()
        print(f"已将《{book_data['book_name']}》的信息保存到数据库")
    except Exception as e:
        print(f"保存到数据库时出错: {e}")
    finally:
        conn.close()


# 初始化数据库和表
init_database()

try:
    # 打开纵横中文网推荐榜单页面
    driver.get("https://www.zongheng.com/rank?nav=recommend&rankType=6")

    # 初始化页面计数器
    current_page = 1
    total_pages = 10  # 根据截图有10页
    processed_books = 0

    while current_page <= total_pages:
        print(f"\n===== 正在处理第 {current_page} 页 =====")

        # 等待页面加载完成
        WebDriverWait(driver, 15).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, ".rank-modules-works--main-item"))
        )

        # 获取当前页所有书籍详情按钮
        book_details_buttons = WebDriverWait(driver, 10).until(
            EC.presence_of_all_elements_located(
                (By.XPATH, '//a[contains(@class, "btn-read-now") and contains(text(), "书籍详情")]'))
        )

        print(f"第 {current_page} 页找到 {len(book_details_buttons)} 本书籍")

        # 记录当前窗口句柄
        main_window = driver.current_window_handle

        # 遍历当前页的每本书
        for i, book_button in enumerate(book_details_buttons):
            print(f"\n处理第 {processed_books + 1} 本书 (本页第 {i + 1} 本)...")

            # 滚动到书籍位置
            driver.execute_script("arguments[0].scrollIntoView({behavior: 'smooth', block: 'center'});", book_button)
            time.sleep(0.5)  # 等待滚动完成

            # 点击书籍详情按钮
            book_button.click()
            print(f"已点击第 {processed_books + 1} 本书的书籍详情，等待新页面加载...")

            # 等待新窗口出现
            WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(2))

            # 切换到新窗口
            for window_handle in driver.window_handles:
                if window_handle != main_window:
                    driver.switch_to.window(window_handle)
                    break

            try:
                # 等待新页面加载完成
                WebDriverWait(driver, 15).until(
                    EC.presence_of_element_located((By.CSS_SELECTOR, ".book-info--title"))
                )
                print("已进入书籍详情页面，开始提取图书信息...")

                # 提取图书信息
                book_data = {}

                # 1. 图书名称
                book_name_element = driver.find_element(By.CSS_SELECTOR, ".book-info--title span")
                book_data['book_name'] = book_name_element.text

                # 2. 状态
                status_element = driver.find_element(By.CSS_SELECTOR, ".serialStatus")
                book_data['status'] = status_element.text

                # 3. 类型
                category_element = driver.find_element(By.CSS_SELECTOR, ".cateFineId")
                book_data['category'] = category_element.text

                # 4. 数据指标（总点击、总推荐、周推荐、总字数）
                nums_elements = driver.find_elements(By.CSS_SELECTOR, ".book-info--nums div")
                if len(nums_elements) >= 4:
                    book_data['total_clicks'] = nums_elements[0].find_element(By.TAG_NAME, "span").text
                    book_data['total_recommendations'] = nums_elements[1].find_element(By.TAG_NAME, "span").text
                    book_data['weekly_recommendations'] = nums_elements[2].find_element(By.TAG_NAME, "span").text
                    book_data['total_words'] = nums_elements[3].find_element(By.TAG_NAME, "span").text

                # 5. 最新章节
                latest_chapter_element = driver.find_element(By.CSS_SELECTOR, ".book-info--chapter-name a")
                book_data['latest_chapter'] = latest_chapter_element.text

                # 打印提取的信息
                print(f"提取到的第 {processed_books + 1} 本图书信息:")
                for key, value in book_data.items():
                    print(f"{key}: {value}")

                # 将数据写入CSV
                with open(csv_file, 'a', newline='', encoding='utf-8-sig') as f:
                    writer = csv.DictWriter(f, fieldnames=fieldnames)
                    writer.writerow(book_data)
                print(f"图书信息已保存到: {csv_file}")

                # 将数据保存到数据库
                save_to_database(book_data)

            except Exception as e:
                print(f"处理第 {processed_books + 1} 本书时出错: {e}")
                # 出错时截图以便调试
                driver.save_screenshot(f"error_screenshot_{processed_books + 1}.png")
                print(f"已保存错误截图: error_screenshot_{processed_books + 1}.png")

            finally:
                # 关闭当前窗口（书籍详情页）
                driver.close()
                print(f"已关闭第 {processed_books + 1} 本书的详情页面")

                # 切回主窗口
                driver.switch_to.window(main_window)

                # 增加随机等待时间 (2-4秒)
                wait_time = random.uniform(2, 4)
                print(f"等待 {wait_time:.1f} 秒后处理下一本书...")
                time.sleep(wait_time)

                # 更新已处理书籍计数
                processed_books += 1

        # 当前页处理完成后，翻到下一页
        if current_page < total_pages:
            print(f"\n准备翻到第 {current_page + 1} 页...")

            # 定位下一页按钮
            next_button = WebDriverWait(driver, 10).until(
                EC.element_to_be_clickable(
                    (By.XPATH, '//button[contains(@class, "btn-next") and not(contains(@class, "disabled"))]'))
            )

            # 滚动到分页器位置
            pagination = driver.find_element(By.CSS_SELECTOR, ".el-pagination")
            driver.execute_script("arguments[0].scrollIntoView();", pagination)

            # 点击下一页按钮
            next_button.click()
            print(f"已点击下一页按钮，等待第 {current_page + 1} 页加载...")

            # 等待新页面加载完成
            WebDriverWait(driver, 15).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, ".rank-modules-works--main-item"))
            )

            # 增加页面间等待时间 (3-5秒)
            wait_time = random.uniform(3, 5)
            print(f"等待 {wait_time:.1f} 秒后开始处理下一页...")
            time.sleep(wait_time)

        # 更新页面计数器
        current_page += 1

    print(f"\n所有 {processed_books} 本书籍处理完成！")

except Exception as e:
    print(f"发生全局错误: {e}")
    # 出错时截图以便调试
    driver.save_screenshot("error_screenshot_main.png")
    print("已保存错误截图: error_screenshot_main.png")

finally:
    # 关闭浏览器
    driver.quit()
    print("浏览器已关闭")